Skip to content

feat: add tenant ban/unban API endpoint#895

Open
mentels wants to merge 6 commits intomainfrom
chore/add-api-for-banning-unbanningt-tenant
Open

feat: add tenant ban/unban API endpoint#895
mentels wants to merge 6 commits intomainfrom
chore/add-api-for-banning-unbanningt-tenant

Conversation

@mentels
Copy link
Contributor

@mentels mentels commented Mar 24, 2026

Summary

  • Adds PATCH /api/tenants/:external_id for banning and unbanning tenants. Banned tenants receive a FATAL wire-level error (EBANNED) on any new connection attempt.
  • Adds banned_at / ban_reason fields to the tenants table via migration, and a TenantBannedError that is checked in ClientHandler.Checks before a connection is established.

https://linear.app/supabase/issue/POOLER-275/support-banning-and-unbanning-tenants-via-http-api

OAS / CastAndValidate scope

OpenApiSpex.Plug.CastAndValidate is scoped to the :patch action only via a conditional plug. PutApiSpec is added to the :api pipeline so the spec is available for casting. Extending CastAndValidate to the remaining actions is left as a TODO for a follow-up PR — those actions currently pass params as string-keyed maps and would require coordinated changes.

TODO

  • make sure the migration that adds the fields is safe for the version of Postgres we run on and won't do the full table scan to fill in NULLs
  • add metric for tracking banned tenants (likely a separate PR)

@mentels mentels requested a review from a team as a code owner March 24, 2026 10:19
Copilot AI review requested due to automatic review settings March 24, 2026 10:19
@mentels mentels marked this pull request as draft March 24, 2026 10:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds tenant-level ban/unban functionality to Supavisor, including an API endpoint for toggling the ban state and a connection-time check that rejects banned tenants with a wire-level FATAL error.

Changes:

  • Adds PATCH /api/tenants/:external_id to ban/unban tenants via OpenAPI-cast body params.
  • Persists ban state via new tenants.banned_at / tenants.ban_reason columns and updates tenant/domain logic accordingly.
  • Enforces bans during connection establishment and adds unit/integration test coverage for the new behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
test/supavisor_web/controllers/tenant_controller_test.exs Adds controller tests for PATCH ban/unban behavior, response fields, and cache invalidation.
test/supavisor/client_handler_test.exs Adds unit tests for the new ban check and wire error formatting.
test/integration/proxy_test.exs Adds integration coverage asserting banned tenants receive a wire-level FATAL error and can connect after unban.
priv/repo/migrations/20260323000000_add_tenant_ban_fields.exs Adds nullable banned_at and ban_reason columns to tenants table.
lib/supavisor_web/router.ex Adds PATCH route and makes ApiSpec available in the :api pipeline.
lib/supavisor_web/open_api_schemas.ex Adds ToggleTenantBan request schema for PATCH endpoint.
lib/supavisor_web/controllers/tenant_controller.ex Implements PATCH action using CastAndValidate + Tenants.toggle_tenant_ban/2.
lib/supavisor/tenants/tenant.ex Adds schema fields and ban/unban changesets.
lib/supavisor/tenants.ex Adds toggle_tenant_ban/2 public API with cache invalidation.
lib/supavisor/errors/tenant_banned_error.ex Introduces TenantBannedError (EBANNED) used for wire-level rejection.
lib/supavisor/client_handler/checks.ex Adds check_tenant_not_banned/1 and wires it into connection checks.
lib/supavisor/client_handler.ex Calls the new ban check before completing connection establishment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

# TODO: fix the other actions to use CastAndValidate and remove this conditional plug
plug OpenApiSpex.Plug.CastAndValidate, [json_render_error_v2: true] when action == :patch
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is useful as this does API params validation for us.

It also facilitates testing as we can assert on schemas etc.

}
)

def patch(conn, %{external_id: id}) when is_boolean(conn.body_params.banned) do
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not happy with the action name but I couldn't come up with anything better than patch; I think update would be better here as this is what the PATCH is meant for but it's already taken.

I envision this action to be used for other tenant modifications too.

@mentels mentels force-pushed the chore/add-api-for-banning-unbanningt-tenant branch 3 times, most recently from b17942e to f633643 Compare March 24, 2026 12:55
Introduces a PATCH /api/tenants/:external_id endpoint for banning and
unbanning tenants. Banned tenants receive a FATAL wire-level error
(EBANNED) on any new connection attempt.

Changes:
- Add PATCH route and patch/2 controller action backed by
  Tenants.toggle_tenant_ban/2
- Add banned_at / ban_reason fields to the tenants table via migration
- Add TenantBannedError and wire it into ClientHandler.Checks so
  connections to banned tenants are rejected at the check stage
- Add ToggleTenantBan OpenAPI schema and register PutApiSpec in the :api
  pipeline; scope CastAndValidate to :patch only (other actions have a
  TODO for a follow-up PR)
- Add controller, unit, and integration tests covering ban/unban,
  boolean-type validation, 404 handling, and cache invalidation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@mentels mentels force-pushed the chore/add-api-for-banning-unbanningt-tenant branch from 5030654 to ea91d69 Compare March 24, 2026 13:29
@mentels mentels marked this pull request as ready for review March 24, 2026 13:29
@mentels mentels force-pushed the chore/add-api-for-banning-unbanningt-tenant branch from 4e802f7 to ac5fec9 Compare March 24, 2026 20:02
Copy link
Member

@v0idpwn v0idpwn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good, but check should be ok with expired bans

mentels and others added 3 commits March 25, 2026 18:03
check_tenant_not_banned/1 now allows connections when banned_until is
set and already in the past (time-limited ban expired). Adds tests for
permanent ban, future expiry, and past expiry cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants